package com.turingoal.license.generator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

/**
 * 加密, 需要分段加密
 * 2048位密钥：
 * 最大明文加密长度（单位：字节）：245
 * 最大密文解密长度（单位：字节）：256
 */
public final class TgLicenseEncryptUtil {
    private TgLicenseEncryptUtil() {
        throw new Error("工具类不能实例化！");
    }

    private static final Logger logger = LoggerFactory.getLogger(TgLicenseGenerator.class); // 日志
    private static final int MAX_ENCRYPT_BLOCK = 245;

    /**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data            源数据
     * @param privateKeyBytes 私钥
     */
    public static byte[] encryptByPrivateKey(final byte[] data, final byte[] privateKeyBytes) {
        byte[] encryptedData = null;
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, privateK);
            int inputLen = data.length;
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            encryptedData = out.toByteArray();
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | IOException e) {
            logger.error("加密失败！");
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
        return encryptedData;
    }

    /**
     * createKeyPair、得到的公钥长度是294
     */
    public static KeyPair createKeyPair() {
        KeyPair keyPair = null;
        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(2048);
            keyPair = keyGen.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            logger.error("获取密钥对失败");
        }
        return keyPair;
    }

    /**
     * getPrivateKeyStr
     */
    public static String getPrivateKeyStr(final KeyPair licenseKeyPair) {
        String privateKeyStr = null;
        if (licenseKeyPair != null) {
            privateKeyStr = Base64.getEncoder().encodeToString(licenseKeyPair.getPrivate().getEncoded()); // 私钥
        }
        return privateKeyStr;
    }

    /**
     * getPublicKeyStr, 长度216
     */
    public static String getPublicKeyStr(final KeyPair licenseKeyPair) {
        String publicKeyStr = null;
        if (licenseKeyPair != null) {
            publicKeyStr = Base64.getEncoder().encodeToString(licenseKeyPair.getPublic().getEncoded()); // 公钥
        }
        return publicKeyStr;
    }
}
